package top.zhenganwen.securitydemo.web.async;

import org.apache.commons.lang.RandomStringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.async.DeferredResult;

import java.util.concurrent.TimeUnit;


/**
 * @author zhenganwen
 * @date 2019/8/7
 * @desc AsyncController
 */
@RestController
@RequestMapping("/order")
public class AsyncOrderController {

    private Logger logger = LoggerFactory.getLogger(getClass());

    // 创建订单
//    @PostMapping
//    public Callable<String> createOrder() {
//        // 生成12位单号
//        String orderNumber = RandomStringUtils.randomNumeric(12);
//        logger.info("[主线程]收到创建订单请求，订单号=>" + orderNumber);
//        Callable<String> result = () -> {
//            logger.info("[副线程]创建订单开始,订单号=>"+orderNumber);
//            // 模拟创建订单逻辑
//            TimeUnit.SECONDS.sleep(3);
//            logger.info("[副线程]创建订单完成，订单号=>" + orderNumber+"，返回结果给客户端");
//            return orderNumber;
//        };
//        logger.info("[主线程]已将请求委托副线程处理(订单号=>" + orderNumber + ")，继续处理其它请求");
//        return result;
//    }

    @Autowired
    private DeferredResultHolder deferredResultHolder;

    @Autowired
    private OrderProcessingQueue orderProcessingQueue;

    // 秒杀系统下单请求
    @PostMapping
    public DeferredResult<String> createOrder() {

        logger.info("【请求线程】收到下单请求");

        // 生成12位单号
        String orderNumber = RandomStringUtils.randomNumeric(12);

        // 创建处理结果凭证放入缓存，以便监听（订单系统向MQ发送的订单处理结果消息的）线程向凭证中设置结果，这会触发该结果响应给客户端
        DeferredResult<String> deferredResult = new DeferredResult<>();
        deferredResultHolder.placeOrder(orderNumber, deferredResult);

        // 异步向MQ发送下单消息，假设需要200ms
        new Thread(() -> {
            try {
                TimeUnit.MILLISECONDS.sleep(500);
                synchronized (orderProcessingQueue) {
                    while (orderProcessingQueue.size() >= Integer.MAX_VALUE) {
                        try {
                            orderProcessingQueue.wait();
                        } catch (Exception e) {
                        }
                    }
                    orderProcessingQueue.addLast(orderNumber);
                    orderProcessingQueue.notifyAll();
                }
                logger.info("向MQ发送下单消息, 单号: {}", orderNumber);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }, "本地临时线程-向MQ发送下单消息")
        .start();

        logger.info("【请求线程】继续处理其它请求");

        // 并不会立即将deferredResult序列化成JSON并返回给客户端，而会等deferredResult的setResult被调用后，将传入的result转成JSON返回
        return deferredResult;
    }
}